package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.user.modules.models.User;
import cn.wizzer.app.user.modules.models.UserTransfer;
import cn.wizzer.app.user.modules.models.enums.BizTypeEnum;
import cn.wizzer.app.user.modules.models.enums.TransferStatusEnum;
import cn.wizzer.app.user.modules.models.vo.UserTransferVo;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.app.user.modules.services.account.UserAccountRecordService;
import cn.wizzer.app.user.modules.services.account.UserTransferService;
import cn.wizzer.framework.base.Result;
import cn.wizzer.framework.base.exceptions.BizException;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import cn.wizzer.framework.base.service.CommonDBService;
import cn.wizzer.framework.page.Pagination;
import cn.wizzer.framework.util.Id;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.*;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;

import java.math.BigDecimal;

@IocBean(args = {"refer:dao"})
@Service(interfaceClass = UserTransferService.class)
public class UserTransferServiceImpl extends BaseServiceImpl<UserTransfer> implements UserTransferService {

    public UserTransferServiceImpl(Dao dao) {
        super(dao);
    }

    @Inject
    private CommonDBService dbService;
    @Inject
    private UserService userService;
    @Inject
    private UserAccountRecordService accountRecordService;

    /**
     * 钻石划转
     *
     * @param appid
     * @param amount
     * @param username
     */
    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void transfer(String appid, BigDecimal amount, String username) {
        // 判断目标用户是否存在，是否有收款权限
        User user = userService.fetch(Cnd.where("userName", "=", username));
        if (null == user) {
            throw new BizException("用户不存在");
        }
        if (!user.isCollect()) {
            throw new BizException("该用户没有收款权限");
        }
        //添加划转记录/暂不设置划转金额
        UserTransfer userTransfer = new UserTransfer();
        userTransfer.setNo(Id.createOrderNo());
        userTransfer.setTransferUserId(appid);
        userTransfer.setCollectUserId(user.getId());
        //设置状态为划转中
        userTransfer.setStatus(TransferStatusEnum.TRANSFERRING);
        userTransfer = this.insert(userTransfer);
        // 当前用户减钻石
        accountRecordService.add(appid, amount, BizTypeEnum.TRANSFER, userTransfer.getId());
        //减钻石成功后更新记录，设置划转金额
        this.update(Chain.make("amount", amount), Cnd.where("id", "=", userTransfer.getId()));
    }

    /**
     * 划转记录确认
     *
     * @param id
     * @param userId
     */
    @Override
    public void transferConfirm(String id, String userId) {
        UserTransfer userTransfer = this.fetch(Cnd.where("id", "=", id)
                .and("collect_user_id", "=", userId)
                .and("delFlag", "=", 0));
        if (userTransfer == null) {
            Result.breakWith("该记录不存在或不属于你，无法确认");
        }
        if (!userTransfer.getStatus().equals(TransferStatusEnum.TRANSFERRING)) {
            Result.breakWith("状态不正确");
        }
        // 确认记录，修改记录状态（目前只修改状态，不给收款用户加钱）
        this.update(Chain.make("status", TransferStatusEnum.RECEIVED).add("opAt", Times.getTS()),
                Cnd.where("id", "=", id));
    }

    /**
     * 划转记录取消
     *
     * @param id
     */
    @Override
    @Aop(TransAop.REPEATABLE_READ)
    public void transferCancel(String id, String userId) {
        UserTransfer userTransfer = this.fetch(Cnd.where("id", "=", id)
                .and("collect_user_id", "=", userId)
                .and("delFlag", "=", 0));
        if (userTransfer == null) {
            Result.breakWith("该记录不存在或不属于你，无法取消");
        }
        if (!userTransfer.getStatus().equals(TransferStatusEnum.TRANSFERRING)) {
            Result.breakWith("状态不正确");
        }
        // 取消记录，修改记录状态，划转金额原路返回
        this.update(Chain.make("status", TransferStatusEnum.RETURNED).add("opAt", Times.getTS()),
                Cnd.where("id", "=", id));

        //金额返回
        accountRecordService.add(userTransfer.getTransferUserId(), userTransfer.getAmount(), BizTypeEnum.TRANSFER_CANCEL, userTransfer.getId());
    }

    /**
     * 转账记录（转出转入）
     *
     * @param pageNumber
     * @param pageSize
     * @param isTransfer    是否为划转记录，不是则为转入记录
     * @param status        状态->-RETURNED:已退回、TRANSFERRING:划转中、RECEIVED:已确认
     * @param userId
     * @param searchKeyword 模糊查询，手机号或用户名或昵称或流水号
     * @param startTime     开始时间
     * @param endTime       结束时间
     * @return
     */
    @Override
    public Pagination listPage(int pageNumber, int pageSize, boolean isTransfer, TransferStatusEnum status, String userId, String searchKeyword, String startTime, String endTime) {
        Sql sql = Sqls.create("SELECT u1.userName as transferUserName, u1.nickName as transferNickName, u1.phone as transferPhone, " +
                "u2.userName as collectUserName, u2.nickName as collectNickName, u2.phone as collectPhone, " +
                "ut.* " +
                "FROM user_transfer ut ");
        Sql countSql = Sqls.create("SELECT COUNT(1) " +
                "FROM user_transfer ut ");
        Sql joinSql = Sqls.create("LEFT JOIN user u1 ON ut.transfer_user_id = u1.id " +
                "LEFT JOIN user u2 ON ut.collect_user_id = u2.id " +
                "$condition ");
        Cnd cnd = Cnd.where("ut.delFlag", "=", 0);
        //判断是否为转账记录，转账记录以转账用户查询，转出记录以到账用户查询
        if (isTransfer) {
            //组装转账记录sql
            assembleTransferSql(cnd, userId, searchKeyword);
        } else {
            //组装到账记录sql
            assembleArriveSql(cnd, userId, searchKeyword);
        }
        if (status != null) {
            cnd.and("ut.status", "=", status);
        }
        if (Strings.isNotBlank(startTime) && Strings.isNotBlank(endTime)) {
            cnd.and("ut.ctAt", ">=", startTime);
            cnd.and("ut.ctAt", "<=", endTime);
        }
        joinSql.setCondition(cnd);
        sql.appendSourceSql(joinSql.toString());
        sql.appendSourceSql("ORDER BY ut.ctAt DESC");
        countSql.appendSourceSql(joinSql.toString());
        return dbService.listPage(UserTransferVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }

    /**
     * 组装转账记录sql
     *
     * @param cnd
     * @param userId
     * @param searchKeyword
     * @return
     */
    public void assembleTransferSql(Cnd cnd, String userId, String searchKeyword) {
        if (Strings.isNotBlank(userId)) {
            cnd.and("ut.transfer_user_id", "=", userId);
        }
        if (Strings.isNotBlank(searchKeyword)) {
            searchKeyword = "%" + searchKeyword + "%";
            cnd.and(Cnd.exps("u2.nickName", "LIKE", searchKeyword)
                    .or("u2.phone", "LIKE", searchKeyword)
                    .or("u2.userName", "LIKE", searchKeyword)
                    .or("ut.no", "LIKE", searchKeyword));
        }
    }

    /**
     * 组装到账记录sql
     *
     * @param cnd
     * @param userId
     * @param searchKeyword
     * @return
     */
    public void assembleArriveSql(Cnd cnd, String userId, String searchKeyword) {
        if (Strings.isNotBlank(userId)) {
            cnd.and("ut.collect_user_id", "=", userId);
        }
        if (Strings.isNotBlank(searchKeyword)) {
            searchKeyword = "%" + searchKeyword + "%";
            cnd.and(Cnd.exps("u1.nickName", "LIKE", searchKeyword)
                    .or("u1.phone", "LIKE", searchKeyword)
                    .or("u1.userName", "LIKE", searchKeyword)
                    .or("ut.no", "LIKE", searchKeyword));
        }
    }

    /**
     * 后台管理查询列表
     *
     * @param pageNumber      页码
     * @param pageSize        页数
     * @param no              流水号模糊查询
     * @param transferKeyword 转出人模糊查询（手机号、昵称、用户名）
     * @param collectKeyword  收款人模糊查询（手机号、昵称、用户名）
     * @param searchDate      时间集合
     * @param status          记录状态
     * @return
     */
    @Override
    public Pagination listPage(int pageNumber, int pageSize, String no, String transferKeyword,
                               String collectKeyword, String[] searchDate, TransferStatusEnum status) {
        Sql sql = Sqls.create("SELECT u1.userName as transferUserName, u1.nickName as transferNickName, u1.phone as transferPhone, " +
                "u2.userName as collectUserName, u2.nickName as collectNickName, u2.phone as collectPhone, " +
                "ut.* " +
                "FROM user_transfer ut ");
        Sql countSql = Sqls.create("SELECT COUNT(1) FROM user_transfer ut ");
        Sql joinSql = Sqls.create("LEFT JOIN user u1 ON ut.transfer_user_id = u1.id " +
                "LEFT JOIN user u2 ON ut.collect_user_id = u2.id " +
                "$condition ");
        Cnd cnd = Cnd.where("ut.delFlag", "=", 0);
        if (Strings.isNotBlank(no)) {
            no = "%" + no + "%";
            cnd.and("ut.no", "LIKE", no);
        }
        if (Strings.isNotBlank(transferKeyword)) {
            transferKeyword = "%" + transferKeyword + "%";
            cnd.and(Cnd.exps("u1.nickName", "LIKE", transferKeyword)
                    .or("u1.phone", "LIKE", transferKeyword)
                    .or("u1.userName", "LIKE", transferKeyword));
        }
        if (Strings.isNotBlank(collectKeyword)) {
            collectKeyword = "%" + collectKeyword + "%";
            cnd.and(Cnd.exps("u2.nickName", "LIKE", collectKeyword)
                    .or("u2.phone", "LIKE", collectKeyword)
                    .or("u2.userName", "LIKE", collectKeyword));
        }
        if (null != searchDate && searchDate.length != 0) {
            cnd.and("ut.ctAt", ">=", Times.d2TS(Times.D(searchDate[0])));
            cnd.and("ut.ctAt", "<=", Times.d2TS(Times.D(searchDate[1])));
        }
        if (status != null) {
            cnd.and("ut.status", "=", status);
        }
        joinSql.setCondition(cnd);
        sql.appendSourceSql(joinSql.toString());
        sql.appendSourceSql("ORDER BY ut.ctAt DESC");
        countSql.appendSourceSql(joinSql.toString());
        return dbService.listPage(UserTransferVo.class, pageNumber, pageSize, sql.toString(), countSql.toString());
    }


}
